using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cmc.Modbus.Base
{
    public static class OtherHelper
    {
        public static int BitToIntOne(BitArray bit)
        {
            int res = 0;
            for (int i = bit.Count - 1; i >= 0; i--)
            {
                res = bit[i] ? res + (1 << i) : res;
            }
            return res;
        }

        /// <summary>
        ///  byte 转 bit数组
        /// </summary>
        /// <param name="bytes">低位在前,高位在后</param>
        /// <returns></returns>
        public static BitArray ToBitArray(byte[] bytes)
        {
            var bitCount = bytes.Length * 8;
            BitArray ba = new BitArray(bitCount);
            for (int i = 0; i < bitCount; ++i)
            {
                ba.Set(i, ((bytes[i / 8] >> (i % 8)) & 0x01) > 0);
            }
            return ba;
        }

        public static BitArray ToBitArray(byte low, byte high)
        {
            return ToBitArray(new[] { low, high });
        }

        public static BitArray ToBitArray(ushort number)
        {
            byte high = (byte)(number / 256);
            byte low = (byte)(number - (high * 256));
            return ToBitArray(low, high);
        }
        /// <summary>
        /// 返回高位在前低位在后
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static HighLowBytes To2Bytes(this int number)
        {
            byte high = (byte)(number / 256);
            byte low = (byte)(number - (high * 256));
            return new HighLowBytes() { High = high, Low = low };
        }

        public static int ByteToInt(byte low, byte high)
        {
            return high * 256 + low;
        }

        /// <summary>
        /// 获取crc 校验字节
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static byte[] GetModbusCrc16(byte[] bytes)
        {
            byte crcRegister_H = 0xFF, crcRegister_L = 0xFF;// 预置一个值为 0xFFFF 的 16 位寄存器

            byte polynomialCode_H = 0xA0, polynomialCode_L = 0x01;// 多项式码 0xA001

            for (int i = 0; i < bytes.Length; i++)
            {
                crcRegister_L = (byte)(crcRegister_L ^ bytes[i]);

                for (int j = 0; j < 8; j++)
                {
                    byte tempCRC_H = crcRegister_H;
                    byte tempCRC_L = crcRegister_L;

                    crcRegister_H = (byte)(crcRegister_H >> 1);
                    crcRegister_L = (byte)(crcRegister_L >> 1);
                    // 高位右移前最后 1 位应该是低位右移后的第 1 位：如果高位最后一位为 1 则低位右移后前面补 1
                    if ((tempCRC_H & 0x01) == 0x01)
                    {
                        crcRegister_L = (byte)(crcRegister_L | 0x80);
                    }

                    if ((tempCRC_L & 0x01) == 0x01)
                    {
                        crcRegister_H = (byte)(crcRegister_H ^ polynomialCode_H);
                        crcRegister_L = (byte)(crcRegister_L ^ polynomialCode_L);
                    }
                }
            }



            return new byte[] { crcRegister_L, crcRegister_H };
        }

        /// <summary>
        /// 末尾添加crc16 校验
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static byte[] AddModbusCrc16(byte[] bytes)
        {
            var crc = GetModbusCrc16(bytes);
            var list = bytes.ToList();
            list.AddRange(crc);
            return list.ToArray();
        }

        /// <summary>
        /// crc16校验
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static bool CheckMobusCrc16(byte[] bytes)
        {
            if (bytes.Length < 3)
            {
                return false;
            }
            var ncheck = bytes.Take(bytes.Length - 2);

            var cmp = bytes.Skip(bytes.Length - 2).Take(2).ToArray();
            var cmp2 = GetModbusCrc16(ncheck.ToArray());
            if (cmp[0] == cmp2[0] && cmp[1] == cmp2[1])
            {
                return true;
            }
            return false;
        }

        public static void AddReadAddressesFrom(this List<AddressRead> addressReads ,int start, int length)
        {
            for (int i = start; i < length; i++)
            {
                addressReads.Add(new AddressRead(i));
            }
        }
     }

    public class HighLowBytes
    {
        public byte High { get; set; } = 0;

        public byte Low { get; set; } = 0;
    }

}
